Services User
services-user (VMID 118, 10.0.0.18) runs ABAIR's user-facing web apps. Each app is its own Docker Compose stack in /opt/apps/<app>/.
| Playbook | ansible/hetzner-main/setup-services-user.yml |
| App definitions | ansible/hetzner-main/services-user-apps/<app>/docker-compose.yml |
| Make targets | setup-services-user, update-services-user, deploy-services-user-apps, enroll-wazuh-services-user |
| Secrets | Docker Registry Password, Webserver htpasswd admin, and one Secure Note per app that needs a .env |
To add an app, see Adding an App.
Apps
Images are 10.0.0.12:5000/<image>:main from the private registry unless stated otherwise.
| App (directory) | Public hostname | Port | .env from Vaultwarden | Notes |
|---|---|---|---|---|
abair_website | abair.ie, www.abair.ie, dev.abair.ie | 3001 | yes | Runs with host networking. A second container, abair_website-preview (tag :preview), serves preview.abair.ie on port 4001. |
litreoir | litreoir.abair.ie | 3002 | no | |
fotheidil | fotheidil.abair.ie | 3003 | no | Front end for the Fotheidil subtitling tool. Host networking. Calls the Fotheidil API on Amergin at 192.168.100.2:4040. |
mileglornanog | mileglornanog.abair.ie | 3005 | no | Image mile-glor-na-nog. Host networking. |
meallanoige | meallanoige.abair.ie | 3009 | no | mao.abair.ie and meallanóige.abair.ie redirect here. |
web_reader_extension | webreader.abair.ie | 3010 | no | Back end for the Webreader browser extension. |
geabaire-web-editor | aac-editor.abair.ie | 3013 | no | |
mao-teacher-portal | mao-portal.abair.ie | 3014 | yes | Sends invite emails through smtp.mailbox.org. |
leigh-dom | leighdom.abair.ie | 3015 | yes | Léigh Dom. Stores its data in a named Docker volume. Uploads are limited to 64 MB. Its .env holds ADMIN_API_TOKEN, for the admin API that CÚL calls. |
abair-api | api.abair.ie/v3/ | 4040 | no | The legacy v3 API, with its own Redis. Calls synthesis-legacy at 10.0.0.21:8002. |
geabaire-api | geabaire-api.abair.ie/v1/, api.geabaire.abair.ie/v1/ | 4041 | yes | Has its own Redis. Board images and icons (./data, ./icons) were copied in by hand and aren't in the repo. |
bat-mirialta | bat-mirialta.abair.ie | 8001 | no | |
giob-geab | giob-geab.abair.ie | 8003 | yes | FastAPI plus a Celery worker and scheduler, with a Redis broker. Uses the :latest tag. 3D model assets (./assets) were copied in by hand. |
"Host networking" means the container uses the VM's network directly, so its port isn't listed in the compose file. The port shown comes from the nginx config.
How apps are deployed
make deploy-services-user-apps runs the playbook's apps tag. It doesn't touch the rest of the VM. For each app in the user_apps list, it:
- copies
services-user-apps/<app>/to/opt/apps/<app>/; - for apps in
user_apps_with_env, fetches the Secure Note<app> .envfrom Vaultwarden and writes it to/opt/apps/<app>/.env(ownerroot:deploy, mode0640); - runs
docker compose pullanddocker compose up -d.
It deploys every app on each run.
If a .env note is missing, empty, or in a collection you don't belong to, the run stops. That keeps an app from starting with an empty .env. Run eval "$(make unlock-bw)" first.
The copy only adds and overwrites files. A file you delete from the repo stays on the VM until you remove it by hand.
Day-to-day code changes usually don't need this target. Each app's own CI builds and pushes a new image, then runs docker compose pull && docker compose up -d on this VM over SSH as the deploy user. See Adding an App → CI/CD.
Only the GitHub runner's key is authorized for deploy on this VM. Apps whose CI runs on the Gitea runner can't deploy here over SSH yet. services-staff authorizes both runners.
Base setup
make setup-services-user and make update-services-user configure the VM itself:
- Docker CE, with the private registry
10.0.0.12:5000allowed as an insecure registry. Docker restarts on every run, which briefly restarts all apps. - A
deployuser, authorized with the GitHub runner's SSH key (fetched live from docker-build). - A registry login for both
rootanddeploy. - Grafana Alloy, which ships container logs and host metrics to Secops.
- UFW (setup only): SSH from anywhere, all ports from the webserver (
10.0.0.14), port 3015 from services-staff (10.0.0.19) for CÚL's Léigh Dom page, everything else denied.
Resource history
- Memory was raised from 4 GB to 8 GB on 2026-08-17.
- The disk was grown from 32 GB to 128 GB on 2026-09-21, live (
qm resizeon the host, thengrowpartandresize2fsin the guest).